home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1997 July / macformat52.iso / mac / Shareware Plus / Comms / ICeTEe 2 / Source (for Programmers only) / ICeTEe.c < prev   
C/C++ Source or Header  |  1997-04-09  |  12KB  |  517 lines

  1. /*    NAME:
  2.         ICeTEe.c
  3.  
  4.     WRITTEN BY:
  5.         Michael Schürig
  6.                 
  7.     DESCRIPTION:
  8.         This file contains a code resource to be installed as a Trap Patch.
  9.  
  10.     NOTES:
  11.         This code is applied as a patch to TEClick.
  12.         If text is command clicked it's launched as a URL with the appropriate
  13.         helper application.
  14.  
  15.     ___________________________________________________________________________
  16. */
  17. //=============================================================================
  18. //        Include files                                                                     
  19. //-----------------------------------------------------------------------------
  20. #include <Gestalt.h>
  21. #include <ToolUtils.h>
  22. #include <Processes.h>
  23. #include <TextEdit.h>
  24. #include <Notification.h>
  25. #include <LowMem.h>
  26. #include <AppleEvents.h>
  27. #include <ICTypes.h>
  28. #include <ICCAPI.h>
  29. #include <ICKeys.h>
  30. #include "A4Stuff.h"
  31. #include "SetupA4.h"
  32. #include "SignatureToApp.h"
  33. #include "ICeTEe Constants.h"
  34. #include "ICeTEe AddrsTable.h"
  35.  
  36.  
  37. //=============================================================================
  38. //        Private defines                                                                 
  39. //-----------------------------------------------------------------------------
  40. #define strMiscErr                1
  41. #define strNoCMErr                2
  42. #define strNoICErr                3
  43. #define strInsufficientICErr    4
  44. #define strNoMemoryErr            5
  45. #define strCantFindHelperErr    6
  46. #define strNoHelperErr            7
  47. #define strNoURLErr                8
  48. #define strCantHackIt            9
  49.  
  50. #define kICBookmarkHelper        "\pHelper•bookmark"
  51.  
  52. #define kCommandKey 55
  53. #define kOptionKey 58
  54.  
  55. #define KeyIsDown(k)( ( (km.arr)[k>>3] >> (k & 7) ) & 1)
  56.  
  57. //=============================================================================
  58. //        Types                                                                 
  59. //-----------------------------------------------------------------------------
  60. typedef pascal void (*TEClickProcPtr)(Point pt, Boolean fExtend, TEHandle teH);
  61. typedef    union {
  62.     UInt8    arr[16];
  63.     KeyMap    map;
  64. } KeyMapArr;
  65.  
  66.  
  67. //=============================================================================
  68. //        Global Variables                                                                 
  69. //-----------------------------------------------------------------------------
  70. TEClickProcPtr    gPrevTEClick;
  71. Handle            gExclusions;
  72. Handle            gErrors;
  73. AEEventClass    gBkEventClass;
  74. AEEventID        gBkEventID;
  75. Boolean            gAlreadyRan = false;
  76.  
  77.  
  78. //=============================================================================
  79. //        Private function prototypes                             
  80. //-----------------------------------------------------------------------------
  81. pascal    void main(Point pt, Boolean fExtend, TEHandle teH);
  82. Boolean    CurrentProcessExcluded(Handle exclusions);
  83. void    MyTEClick(TEHandle teH, short oldSelStart, short oldSelEnd, Boolean makeBookmark);
  84. ICError    DoCommandClick(TEHandle teH, long selStart, long selEnd, Boolean makeBookmark);
  85. pascal ICError AddBookmark(internetConfigurationComponent inst, Ptr urlP, long len);
  86. void    GetIndStrH(Str255 s, Handle h, short index);
  87. pascal void    MyNMResponseProc(NMRecPtr nm);
  88.  
  89.  
  90. //=============================================================================
  91. //        CurrentProcessExcluded : Check if URL clicking is disabled for this app.                                                                 
  92. //-----------------------------------------------------------------------------
  93. Boolean CurrentProcessExcluded(Handle exclusions)
  94. {
  95.     ProcessSerialNumber    PSN;
  96.     ProcessInfoRec        info;
  97.     int                    i;
  98.     Boolean                exclude = true;
  99.  
  100. #if qDebug >= 2
  101.     DebugStr("\pCurrentProcessExcluded entered");
  102. #endif
  103.  
  104.     PSN.highLongOfPSN = 0;
  105.     PSN.lowLongOfPSN = kCurrentProcess;
  106.     
  107.     info.processInfoLength = sizeof(ProcessInfoRec);
  108.     info.processName = nil;
  109.     info.processAppSpec = nil;
  110.     
  111.     if ( GetProcessInformation(&PSN, &info) == noErr )
  112.     {
  113.         exclude = false;
  114.         for (i = 0; i < GetHandleSize(exclusions) / sizeof(OSType); i++)
  115.         {
  116.             if ( (* (OSType **)exclusions)[i] == info.processSignature )
  117.             {
  118.                 exclude = true;
  119.                 break;
  120.             }
  121.         }
  122.     }
  123.  
  124. #if qDebug >= 2
  125.     DebugStr("\pCurrentProcessExcluded exit");
  126. #endif
  127.  
  128.     return(exclude);
  129. }
  130.  
  131.  
  132. //=============================================================================
  133. //        GetIndStrH : GetIndString analog for Handles instead of Resources.                                             
  134. //-----------------------------------------------------------------------------
  135. void    GetIndStrH(Str255 str, Handle h, short index)
  136. {
  137. #if qDebug >= 2
  138.     DebugStr("\pGetIndStrH entered");
  139. #endif
  140.  
  141.     if (h != nil)
  142.     {
  143.         short        count;
  144.         short        i;
  145.         StringPtr    strP;
  146.  
  147.         count = **(short**)h;
  148.         
  149.         if ( 1 <= index && index <= count )
  150.         {
  151.             strP = (StringPtr)*h + sizeof(short);
  152.             
  153.             for (i = 1; i < index; i++)
  154.             {
  155.                 strP += StrLength(strP) + 1;
  156.             }
  157.             BlockMoveData(strP, str, StrLength(strP) + 1);
  158.         }
  159.         else
  160.         {
  161.             str[0] = 0;
  162.         }
  163.     }
  164.     else
  165.     {
  166.             str[0] = 0;
  167.     }
  168.     
  169. #if qDebug >= 2
  170.     DebugStr("\pGetIndStrH exit");
  171. #endif
  172. }
  173.  
  174.  
  175. //=============================================================================
  176. //        MyNMResponseProc : Notification response & cleanup.                                                                 
  177. //-----------------------------------------------------------------------------
  178. pascal void    MyNMResponseProc(NMRecPtr nm)
  179. {
  180.     THz        oldZone;
  181.     Handle    strH;
  182.  
  183.     NMRemove(nm);
  184.  
  185.     oldZone = GetZone();
  186.     SetZone(SystemZone());
  187.     
  188.     strH = RecoverHandle((Ptr)(nm->nmStr));
  189.     if (strH != nil)
  190.         DisposeHandle(strH);
  191.  
  192.     DisposePtr((Ptr)nm);    
  193.     
  194.     SetZone(oldZone);
  195. }
  196.  
  197.  
  198. //=============================================================================
  199. //        MyTEClick : TEClick addition.                                                                 
  200. //-----------------------------------------------------------------------------
  201. void    MyTEClick(TEHandle teH, short oldSelStart, short oldSelEnd, Boolean makeBookmark)
  202. {
  203.     ICError            err;
  204.     
  205. #if qDebug >= 1
  206.     DebugStr("\pMyTEClick entered");
  207. #endif
  208.  
  209.     if ( !CurrentProcessExcluded(gExclusions) )
  210.     {
  211.         
  212.         if ( !(        (oldSelStart <= (**teH).selStart) && ((**teH).selStart <= oldSelEnd)
  213.                 &&    (oldSelStart <= (**teH).selEnd) && ((**teH).selEnd <= oldSelEnd) ) )
  214.         {
  215.             oldSelStart = (**teH).selStart;
  216.             oldSelEnd = (**teH).selEnd;
  217.         }
  218.         
  219.         err = DoCommandClick(teH, oldSelStart, oldSelEnd, makeBookmark);
  220.         
  221.         if (err != noErr)
  222.         {
  223.             Str255            errStr;
  224.             StringHandle    errStrH;
  225.             short            errStrIdx;
  226.             Str32            errNumStr;
  227.             NMRecPtr        nm;
  228.             
  229.             switch (err) {
  230.             
  231.                 case badComponentInstance:
  232.                     errStrIdx = strNoCMErr;
  233.                     break;
  234.                 case badComponentSelector:
  235.                     errStrIdx = strInsufficientICErr;
  236.                     break;
  237.                 case memFullErr:
  238.                     errStrIdx = strNoMemoryErr;
  239.                     break;
  240.                 case afpItemNotFound:
  241.                     errStrIdx = strCantFindHelperErr;
  242.                     break;
  243.                 case icPrefNotFoundErr:
  244.                     errStrIdx = strNoHelperErr;
  245.                     break;
  246.                 case icNoURLErr:
  247.                     errStrIdx = strNoURLErr;
  248.                     break;
  249.                 case noPortErr:
  250.                     errStrIdx = strCantHackIt;
  251.                     break;
  252.                 default:
  253.                     errStrIdx = strMiscErr;
  254.                     break;
  255.             }
  256.             
  257.             GetIndStrH(errStr, gErrors, errStrIdx);
  258.             errStrH = NewString(errStr);
  259.  
  260.             NumToString(err, errNumStr);
  261.             
  262.             Munger((Handle)errStrH, 0, "^0", 2, &errNumStr[1], StrLength(errNumStr));
  263.             
  264.             HLock((Handle)errStrH);
  265.             
  266.             nm = (NMRecPtr)NewPtrSysClear(sizeof(NMRec));
  267.             if (nm != nil)
  268.             {
  269.                 nm->qType = nmType;
  270.                 nm->nmMark = 0;
  271.                 nm->nmIcon = nil;
  272.                 nm->nmSound = nil;
  273.                 nm->nmStr = *errStrH;
  274.                 nm->nmResp = MyNMResponseProc;
  275.                 err = NMInstall(nm);
  276.             }
  277.             else
  278.             {
  279.                 SysBeep(10);
  280.                 DisposeHandle((Handle)errStrH);
  281.             }
  282.         }
  283.     }
  284.         
  285.         
  286. #if qDebug >= 1
  287.     DebugStr("\pMyTEClick exit");
  288. #endif
  289.  
  290. }
  291.  
  292.  
  293. //=============================================================================
  294. //        DoCommandClick : Handle the click.                                                                 
  295. //-----------------------------------------------------------------------------
  296. ICError    DoCommandClick(TEHandle teH, long selStart, long selEnd, Boolean makeBookmark)
  297. {
  298.     ComponentInstance    inst;
  299.     ICError                err, err2;
  300.  
  301.     
  302. #if qDebug >= 1
  303.     DebugStr("\pDoCommandClick entered");
  304. #endif
  305.  
  306.     err = ICCStart(&inst, kCreator);
  307.  
  308.     if (err == noErr)
  309.     {
  310.         err = ICCFindConfigFile(inst, 0, nil);
  311.         if (err == noErr)
  312.         {
  313.             Handle        textH;
  314.             SInt8        s;
  315.             StringPtr    hint, at;
  316.             Handle        urlH;
  317.             long        tmpSelStart = selStart;
  318.             long        tmpSelEnd = selEnd;    
  319.             
  320.             textH = (Handle)TEGetText(teH);
  321.             s = HGetState(textH);
  322.             HLock(textH);
  323.         
  324.             urlH = NewHandle(0);
  325.             
  326.             hint = "\pmailto";
  327.             
  328.             err = ICCParseURL(inst, hint, *textH, GetHandleSize(textH), &tmpSelStart, &tmpSelEnd, urlH);
  329.             
  330.             if (err == noErr)
  331.             {
  332.                 hint = "\p";
  333.                 at = "\p@";
  334.                 
  335.                 if ( Munger(urlH, 0, &at[1], StrLength(at), nil, 0) >= 0 )
  336.                 {
  337.                     hint = "\pmailto";
  338.                 }
  339.                 
  340.                 if (makeBookmark)
  341.                 {
  342.                     err = AddBookmark(inst, (*textH) + tmpSelStart, tmpSelEnd - tmpSelStart);
  343.                     TESetSelect(tmpSelStart, tmpSelEnd, teH);
  344.                 }
  345.                 else
  346.                 {
  347.                     err = ICCLaunchURL(inst, hint, *textH, GetHandleSize(textH), &selStart, &selEnd);
  348.                     TESetSelect(selStart, selEnd, teH);
  349.                 }
  350.             }
  351.             
  352.             DisposeHandle(urlH);
  353.                         
  354.             if (err == noErr)
  355.             {
  356.                 SInt32    junk;
  357.                 SInt16    i = LMGetMenuFlash();
  358.                 
  359.                 while (i--)
  360.                 {
  361.                     Delay(5, &junk);
  362.                     TEDeactivate(teH);
  363.                     Delay(5, &junk);
  364.                     TEActivate(teH);                    
  365.                 }
  366.             }
  367.             HSetState(textH, s);
  368.         }
  369.         err2 = ICCStop(inst);
  370.         
  371.         if (err == noErr)
  372.             err = err2;
  373.     }
  374.  
  375. #if qDebug >= 1
  376.     DebugStr("\pDoCommandClick exit");
  377. #endif
  378.  
  379.     return(err);
  380. }
  381.  
  382.  
  383. //=============================================================================
  384. //        AddBookmark : Send a bookmark event to the bookmark app.                                 
  385. //-----------------------------------------------------------------------------
  386. pascal ICError AddBookmark(internetConfigurationComponent inst, Ptr urlP, long len)
  387. {
  388.     ICAttr                junkAttr;
  389.     ICAppSpec            bookmHelper;
  390.     long                helperSize;
  391.     ProcessSerialNumber    psn;
  392.     ICError                err;
  393.     
  394. #if qDebug >= 1
  395.     DebugStr("\pAddBookmark entered");
  396. #endif
  397.  
  398.     helperSize = sizeof(bookmHelper);
  399.     err = ICCGetPref(inst, kICBookmarkHelper, &junkAttr, (void *)&bookmHelper, &helperSize);
  400.     
  401.  
  402.     err = SignatureToApp(bookmHelper.fCreator, nil, &psn, nil, nil,
  403.                         Sig2App_LaunchApplication, launchContinue | launchDontSwitch);
  404.  
  405.  
  406.     if (err == noErr)
  407.     {
  408.         AEAddressDesc    target;
  409.         
  410.         err = AECreateDesc(typeProcessSerialNumber, &psn, sizeof(psn), &target);
  411.         if (err == noErr)
  412.         {
  413.             AppleEvent        theEvent;
  414.     
  415.             err = AECreateAppleEvent(gBkEventClass, gBkEventID, &target, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);        
  416.             if (err == noErr)
  417.             {
  418.                 char *u = urlP;
  419.                 long l = len;
  420.                 
  421.                 if (u[0] == '<')
  422.                 {
  423.                     u++;
  424.                     l--;
  425.                 }
  426.                 if (u[l-1] == '>')
  427.                     l--;
  428.                 
  429.                 err = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, u, l);
  430.                 if (err == noErr)
  431.                 {
  432.                     AppleEvent    reply;
  433.                     err = AESend(&theEvent, &reply, kAENoReply, kAEHighPriority, kNoTimeOut, nil, nil);
  434.                 }                
  435.                 AEDisposeDesc(&theEvent);
  436.             }
  437.             AEDisposeDesc(&target);
  438.         }
  439.     }
  440. #if qDebug >= 1
  441.     DebugStr("\pAddBookmark exit");
  442. #endif
  443.  
  444.     return err;
  445. }
  446.  
  447.  
  448. //=============================================================================
  449. //        main : Entry point to our code resource.                                                                 
  450. //-----------------------------------------------------------------------------
  451. pascal void main(Point pt, Boolean fExtend, TEHandle teH)
  452. {
  453.     long                oldA4;
  454.     short                oldSelStart, oldSelEnd;
  455.     KeyMapArr            km;
  456.     Boolean                commandKey;
  457.     Boolean                optionKey;
  458.     
  459.     // Set up A4
  460. #ifndef powerc
  461.     oldA4 = SetCurrentA4();
  462. #endif
  463.     
  464. #if qDebug >= 2
  465.     DebugStr("\pICeTEe entered");
  466. #endif
  467.  
  468.     // Save old selection    
  469.     oldSelStart = (**teH).selStart;
  470.     oldSelEnd = (**teH).selEnd;
  471.     
  472.     // Get modifier keys
  473.     GetKeys(km.map);
  474.     commandKey = KeyIsDown(kCommandKey);
  475.     optionKey = KeyIsDown(kOptionKey);
  476.     
  477.         
  478.     // If we've not already been called, do our one time initialisation stuff
  479.     if (!gAlreadyRan)
  480.     {
  481.         ICeTEeAddressTable    *theAddressTable;
  482.         
  483.         Gestalt(kICeTEeAddressTable, (long *) &theAddressTable);        
  484.         gPrevTEClick    = (TEClickProcPtr) ((long) theAddressTable->theTable[kTEClick]);
  485.         gExclusions        = theAddressTable->exclusions;
  486.         gErrors            = theAddressTable->errors;
  487.         gBkEventClass    = theAddressTable->bkEventClass;
  488.         gBkEventID        = theAddressTable->bkEventID;
  489.         gAlreadyRan        = true;
  490.     }
  491.  
  492.     // Call the original TEClick()
  493.     gPrevTEClick(pt, fExtend, teH);
  494.  
  495.     // Do our thing
  496.     if (commandKey)
  497.     {
  498.         THz    oldZone;
  499.  
  500.         oldZone = GetZone();
  501.         SetZone(SystemZone());
  502.         
  503.         MyTEClick(teH, oldSelStart, oldSelEnd, optionKey);
  504.         
  505.         SetZone(oldZone);
  506.     }
  507.  
  508. #if qDebug >= 2
  509.     DebugStr("\pICeTEe exit");
  510. #endif
  511.  
  512.     // Restore A4 and return
  513. #ifndef powerc
  514.     SetA4(oldA4);
  515. #endif
  516. }
  517.